package com.onesports.intelligent.k12.polarlight.service.sys;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.onesports.framework.kit.common.util.BeanUtils;
import com.onesports.framework.kit.common.util.ParamUtils;
import com.onesports.intelligent.k12.polarlight.common.domain.entity.BaseEntity;
import com.onesports.intelligent.k12.polarlight.common.errors.exceptions.BusinessException;
import com.onesports.intelligent.k12.polarlight.common.utils.Assert;
import com.onesports.intelligent.k12.polarlight.constant.BizConstants;
import com.onesports.intelligent.k12.polarlight.constant.CacheConstants;
import com.onesports.intelligent.k12.polarlight.domain.dto.common.EditStatusDTO;
import com.onesports.intelligent.k12.polarlight.domain.dto.common.IdDTO;
import com.onesports.intelligent.k12.polarlight.domain.dto.common.PwdDTO;
import com.onesports.intelligent.k12.polarlight.domain.dto.sys.PasswordChangeDTO;
import com.onesports.intelligent.k12.polarlight.domain.entity.sys.Account;
import com.onesports.intelligent.k12.polarlight.domain.vo.sys.AccountVO;
import com.onesports.intelligent.k12.polarlight.domain.vo.sys.PersonalCenterDetailVO;
import com.onesports.intelligent.k12.polarlight.mapper.organization.OrganizationCampusMapper;
import com.onesports.intelligent.k12.polarlight.mapper.organization.OrganizationMapper;
import com.onesports.intelligent.k12.polarlight.mapper.organization.OrganizationStaffMapper;
import com.onesports.intelligent.k12.polarlight.mapper.sys.AccountMapper;
import com.onesports.intelligent.k12.polarlight.security.OrganizationNotActivatedException;
import com.onesports.intelligent.k12.polarlight.service.organization.StaffService;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections.CollectionUtils;
import org.springframework.cache.annotation.CacheEvict;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.DigestUtils;

import java.util.List;

/**
 * @author Wsy
 **/
@Service
@RequiredArgsConstructor
@Slf4j
public class AccountService extends ServiceImpl<AccountMapper, Account> {

    private final PasswordEncoder passwordEncoder;
    private final AccountMapper accountMapper;
    private final RoleService roleService;
    private final OrganizationCampusMapper campusMapper;
    private final OrganizationStaffMapper staffMapper;
    private final OrganizationMapper organizationMapper;
    private final StaffService staffService;
    private final DataScopeService dataScopeService;


    /**
     * 首次登录修改密码
     *
     * @param dto       入参
     * @param accountId 当前登录用户账号id
     */
    public void firstUpdatePwd(PwdDTO dto, String accountId) {
        //根据id获取当前登录用户
        Account account = this.accountMapper.selectById(accountId);
        Assert.notNull(account, "用户不存在");
        //校验密码是否和原密码相同
        if (this.passwordEncoder.matches(dto.getPassword(), account.getPassword())) {
            throw new BusinessException("新密码不能同原密码相同！");
        }
        //更改密码
        String newPwd = this.passwordEncoder.encode(dto.getPassword());
        account.setPassword(newPwd);
        account.setPasswdUpdated(true);
        this.updateById(account);


    }

    /**
     * 添加账号
     *
     * @param account 账号data
     * @return Account 账号
     */
    public Account add(Account account) {
        if (ParamUtils.isEmpty(account.getPassword())) {
            String md5 = DigestUtils.md5DigestAsHex(BizConstants.DEFAULT_PWD.getBytes());
            String pwd = this.passwordEncoder.encode(md5);
            account.setPassword(pwd);
        } else {
            //密码加密
            account.setPassword(this.passwordEncoder.encode(account.getPassword()));
        }
        //保存数据
        this.accountMapper.insert(account);
        return account;
    }

    /**
     * 修改账号
     *
     * @param account
     */
    public void update(Account account) {
        this.accountMapper.updateById(account);
    }


    /**
     * 重置密码
     *
     * @param dto 入参
     */
    public void resetPwd(IdDTO dto) {
        Account account = new Account();
        account.setId(dto.getId());
        String md5 = DigestUtils.md5DigestAsHex(BizConstants.DEFAULT_PWD.getBytes());
        String pwd = this.passwordEncoder.encode(md5);
        account.setPassword(pwd);
        this.update(account);
    }

    /**
     * 分页查询账号
     *
     * @param page     分页参数
     * @param phone    手机号
     * @param username 姓名
     * @return IPage<Account>
     */
    public IPage<Account> page(Page<Account> page, String phone, String username, Boolean status, String gender, List<String> organizationIds) {
        //角色id筛选条件
        return this.accountMapper.selectPage(page, new QueryWrapper<Account>().lambda()
                .like(ParamUtils.isNotEmpty(phone), Account::getPhone, phone)
                .like(ParamUtils.isNotEmpty(username), Account::getUsername, username)
                .eq(ParamUtils.isNotEmpty(status), Account::getStatus, status)
                .eq(ParamUtils.isNotEmpty(gender), Account::getGender, gender)
                .in(Account::getOrganizationId, organizationIds)
                .orderByDesc(BaseEntity::getCreatedDate));
    }


//    /**
//     * 校验账号是否存在
//     *
//     * @param phone     手机号
//     * @param accountId 账号id
//     */
//    public void checkExist(String phone, String accountId, Boolean status) {
//        Account account = this.accountMapper.selectOne(new QueryWrapper<Account>().lambda()
//                .eq(Account::getPhone, phone)
//                .ne(ParamUtils.isNotEmpty(accountId), BaseEntity::getId, accountId)
//                .eq(BaseEntity::getDeleted, false)
//                .eq(ParamUtils.isNotEmpty(status), Account::getStatus, status));
//        if (account != null) {
//            throw new BusinessException("当前账号已存在!");
//        }
//    }

    public void checkExist(String phone, String orgId, String accountId, Boolean status) {
        LambdaQueryWrapper<Account> wrapper = new QueryWrapper<Account>().lambda()
                .eq(Account::getPhone, phone)
                .ne(ParamUtils.isNotEmpty(accountId), BaseEntity::getId, accountId)
                .eq(BaseEntity::getDeleted, false)
                .eq(ParamUtils.isNotEmpty(status), Account::getStatus, status);
        if(!BizConstants.OPERATION_ORGANIZATION_ID.equals(orgId)){
            wrapper.ne(Account::getOrganizationId, orgId)
                    .ne(Account::getOrganizationId,BizConstants.OPERATION_ORGANIZATION_ID);
        }else{
            wrapper.eq(Account::getOrganizationId, orgId);
        }
        Account account = this.accountMapper.selectOne(wrapper);
        if (account != null) {
            throw new BusinessException("当前账号已存在!");
        }
    }

    public Account getOperationAccount(String phone) {
        return this.accountMapper.selectOne(new QueryWrapper<Account>().lambda()
                .eq(Account::getPhone, phone)
                .eq(Account::getOrganizationId, BizConstants.OPERATION_ORGANIZATION_ID));
    }

    public Account verifyOrganization(String phone) {
        List<Account> accounts = listOrgsByKeyParams(phone, true);
        if (CollectionUtils.isNotEmpty(accounts)) {
            Account account = accounts.get(0);
            if (account.getOrganizationStatus() != null && !account.getOrganizationStatus()) {
                throw new OrganizationNotActivatedException("当前运营团队已经被停用，无法登录!");
            }
            return accounts.get(0);
        } else {
            throw new OrganizationNotActivatedException("用户名或密码错误");
        }
    }

    public List<Account> listOrgsByKeyParams(String phone, Boolean status) {
        return accountMapper.listOrgsByKeyParams(phone, status);
    }

    @Deprecated
    public Account getByPhoneNsystemCode(String phone, String systemCode) {
        return this.accountMapper.getByPhoneNsystemCode(phone);
    }


    /**
     * 查询账号详细信息
     *
     * @param id
     * @return
     */
    public AccountVO findInfo(String id) {
        Account account = accountMapper.selectById(id);
        Assert.notNull(account, "用户不存在");
        return BeanUtils.copyProperties(account, AccountVO.class);
    }

    /**
     * 密码修改
     *
     * @param dto
     */
    @Transactional(rollbackFor = Exception.class)
    public void updatePwd(PasswordChangeDTO dto) {
        Account account = accountMapper.selectById(dto.getId());
        Assert.notNull(account, "用户不存在");
        //校验密码是否和原密码相同
        if (!passwordEncoder.matches(dto.getCurrentPassword(), account.getPassword())) {
            throw new BusinessException("原密码错误");

        }
        if (this.passwordEncoder.matches(dto.getNewPassword(), account.getPassword())) {
            throw new BusinessException("新密码不能同原密码相同！");
        }
        //更改密码
        String newPwd = this.passwordEncoder.encode(dto.getNewPassword());
        account.setPassword(newPwd);
        account.setPasswdUpdated(true);
        this.updateById(account);
    }

    /**
     * 根据手机号重置密码
     *
     * @param contactPhone 手机号
     */
    public void resetPwdByPhone(String contactPhone, Boolean status) {
        LambdaUpdateWrapper<Account> accountUpdate = new LambdaUpdateWrapper<>();
        String md5 = DigestUtils.md5DigestAsHex(BizConstants.DEFAULT_PWD.getBytes());
        String pwd = this.passwordEncoder.encode(md5);
        accountUpdate.eq(Account::getPhone, contactPhone)
                .eq(Account::getStatus, status)
                .set(Account::getPassword, pwd);
        this.accountMapper.update(null, accountUpdate);
    }

    /**
     * 更改启用状态
     *
     * @param dto 入参
     */
    @CacheEvict(cacheNames = CacheConstants.TOKEN, key = "#dto.id",
            cacheResolver = "tokenEvictCacheResolver",
            condition = "#dto.status == false")
    public void updateStatus(EditStatusDTO dto) {
        Account account = new Account();
        account.setId(dto.getId());
        account.setStatus(dto.getStatus());
        this.accountMapper.updateById(account);
        //更改角色成员数量
        this.roleService.updateRoleMemberAmount(account.getId(), account.getStatus());
    }


    /**
     * 个人中心详情
     *
     * @param accountId 账号id
     * @return
     */
    public PersonalCenterDetailVO detail(String accountId) {
        Account account = accountMapper.selectById(accountId);
        PersonalCenterDetailVO vo = BeanUtils.copyProperties(account, PersonalCenterDetailVO.class);
        vo.setRoleList(accountMapper.getRole(accountId));
        vo.setCampusList(campusMapper.getCampus(accountId));
        return vo;
    }

    public List<String> listCampusPermission(String accountId, String orgId, String staffId) {
        List<String> staffPermissions = staffService.listCampusPermission(staffId, orgId);
        List<String> campus = dataScopeService.listDataScopeWithCampus(accountId);
        if (staffPermissions == null) {
            return campus;
        } else if (campus == null) {
            return staffPermissions;
        } else {
            return (List<String>) CollectionUtils.union(staffPermissions, campus);
        }
    }
}
